home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MATHS / PLPLOT / PLPLOT.ZIP / src / plcore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-14  |  53.3 KB  |  2,186 lines

  1. /* $Id: plcore.c,v 1.39 1994/08/25 04:06:26 mjl Exp $
  2.  * $Log: plcore.c,v $
  3.  * Revision 1.39  1994/08/25  04:06:26  mjl
  4.  * Moved call of plClrCWindows() to plP_eop where it belongs.
  5.  *
  6.  * Revision 1.38  1994/08/10  05:30:18  mjl
  7.  * Reversed the order of stream destruction when plend() is called -- now the
  8.  * last-created stream gets destroyed first.  Makes more sense this way and
  9.  * works more robustly with the x14c demo.
  10.  *
  11.  * Revision 1.37  1994/07/12  19:20:31  mjl
  12.  * Two bugs fixed: cmap1 palette should now "stick" on plots saved from Tk
  13.  * driver, and the code won't complain when a bop isn't preceded by an eop.
  14.  *
  15.  * Revision 1.36  1994/07/08  22:50:31  mjl
  16.  * Fixed bug that was hosing the background color in plots saved from the
  17.  * Tk/DP driver menu.
  18.  *
  19.  * Revision 1.35  1994/07/03  05:50:22  mjl
  20.  * Added fix to prevent an infinite loop while exiting under certain error
  21.  * conditions, submitted by Radey Shouman.
  22.  *
  23.  * Revision 1.34  1994/07/02  21:32:11  mjl
  24.  * Ensure that fflush() is never called with a null pointer, since some
  25.  * systems don't like it (submitted by Neal Holtz).
  26.  *
  27.  * Revision 1.33  1994/06/30  18:26:16  mjl
  28.  * All core source files: made another pass to eliminate warnings when using
  29.  * gcc -Wall.  Lots of cleaning up: got rid of includes of math.h or string.h
  30.  * (now included by plplot.h), and other minor changes.  Now each file has
  31.  * global access to the plstream pointer via extern; many accessor functions
  32.  * eliminated as a result.  Driver interface changed to keep track of current
  33.  * status; plsc->status is set to one of AT_BOP, DRAWING, or AT_EOP.  This
  34.  * makes it easy to catch missing plbop/pleop's, and to collapse multiple
  35.  * plbop's or pleop's into a single one.  Subpage initialization code moved
  36.  * to plpage.c.
  37.  *
  38.  * Revision 1.32  1994/06/09  20:31:30  mjl
  39.  * Small changes to the way plmkstrm() works.
  40.  *
  41.  * Revision 1.31  1994/05/07  03:23:07  mjl
  42.  * Eliminated some obsolete operations involving fgcolor and bgcolor.
  43.  *
  44.  * Revision 1.30  1994/04/30  16:15:06  mjl
  45.  * Fixed format field (%ld instead of %d) or introduced casts where
  46.  * appropriate to eliminate warnings given by gcc -Wall.
  47.  *
  48.  * Revision 1.29  1994/04/08  12:31:39  mjl
  49.  * Removed driver interface handling of nopause (it was a bad idea).  Added
  50.  * call to (*plsc->tidy) [if defined] in plP_tidy.  Added a function
  51.  * plsMouseEH for setting the mouse event handler (contributed by Radey
  52.  * Shouman).
  53.  *
  54.  * Revision 1.28  1994/03/23  08:02:48  mjl
  55.  * Provided for handling more basic operations in the driver interface rather
  56.  * than the drivers themselves (pls->nopause, resetting stream parameters
  57.  * after a tidy, etc).  Added support for hardware fill -- if the device does
  58.  * not support the operation, the function plfill_soft is used instead.
  59.  * Pattern fill number set/get access functions added.
  60.  *
  61.  * Many debugging remnants from driver interface development removed.
  62.  *
  63.  * Many functions moved elsewhere (this file has gotten too large):
  64.  *
  65.  *     plwarn plexit plcol0 plcol1 plrgb plrgb1 plscolbg plscol0 plgcol0
  66.  *     plscmap1 plscmap1f1 plscolor
  67.  *
  68.  * Revision 1.27  1994/01/25  06:23:26  mjl
  69.  * Moved default setting of digits variables to the correct location.
  70.  *
  71.  * Revision 1.26  1994/01/18  06:01:38  mjl
  72.  * Now set default number of digits in numeric labels for axis to be switched
  73.  * to scientific notation.  Before this capability had to be enabled by the
  74.  * user.  The number of digits defaults to x:4, y:4, z:3 (xy or xyz plots).
  75.  *
  76.  * Revision 1.25  1994/01/17  21:36:51  mjl
  77.  * Added function c_plgcol0 for retrieving RGB color values from cmap0
  78.  * entries.  User-contributed (I lost track of who sent it).
  79. */
  80.  
  81. /*    plcore.c
  82.  
  83.     Central dispatch facility for plplot.
  84.     Also contains the plplot main data structures, external access
  85.     routines, and initialization calls.
  86.  
  87.     This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
  88. */
  89.  
  90. #include "plcore.h"
  91.  
  92. /*----------------------------------------------------------------------*\
  93.  * Driver Interface
  94.  *
  95.  * These routines are the low-level interface to the driver -- all calls
  96.  * to driver functions must pass through here.  For implementing driver-
  97.  * specific functions, the escape function is provided.  The command
  98.  * stream gets duplicated to the plot buffer here.
  99.  *
  100.  * All functions that result in graphics actually being plotted (rather
  101.  * than just a change of state) are filtered as necessary before being
  102.  * passed on.  The default settings do not require any filtering, i.e.
  103.  * plplot physical coordinates are the same as the device physical
  104.  * coordinates (currently this can't be changed anyway), and a global view
  105.  * equal to the entire page is used.
  106.  *
  107.  * The reason one wants to put view-specific filtering here is that if
  108.  * enabled, the plot buffer should receive the unfiltered data stream.
  109.  * This allows a specific view to be used from an interactive device
  110.  * (e.g. TCL/TK driver) but be restored to the full view at any time
  111.  * merely by reprocessing the contents of the plot buffer.
  112.  *
  113.  * The metafile, on the other hand, *should* be affected by changes in the
  114.  * view, since this is a crucial editing capability.  It is recommended
  115.  * that the initial metafile be created without a restricted global view,
  116.  * and modification of the view done on a per-plot basis as desired during
  117.  * subsequent processing.
  118.  *
  119. \*----------------------------------------------------------------------*/
  120.  
  121. enum {AT_BOP, DRAWING, AT_EOP};
  122.  
  123. /* Initialize device. */
  124. /* The plot buffer must be called last */
  125.  
  126. void
  127. plP_init(void)
  128. {
  129.     plsc->status = AT_EOP;
  130.  
  131.     offset = plsc->device - 1;
  132.     (*dispatch_table[offset].pl_init) (plsc);
  133.  
  134.     if (plsc->plbuf_write)
  135.     plbuf_init(plsc);
  136. }
  137.  
  138. /* End of page */
  139. /* The plot buffer must be called first */
  140. /* Ignore instruction if there's nothing drawn */
  141.  
  142. void
  143. plP_eop(void)
  144. {
  145.     if (plsc->status != DRAWING)
  146.     return;
  147.  
  148.  
  149.     plsc->status = AT_EOP;
  150.  
  151.     if (plsc->plbuf_write)
  152.     plbuf_eop(plsc);
  153.  
  154.     offset = plsc->device - 1;
  155.     (*dispatch_table[offset].pl_eop) (plsc);
  156.  
  157.     plClrCWindows();
  158. }
  159.  
  160. /* Set up new page. */
  161. /* The plot buffer must be called last */
  162. /* Ignore if the bop was already issued. */
  163. /* It's not actually necessary to be AT_EOP here, so don't check for it. */
  164.  
  165. void
  166. plP_bop(void)
  167. {
  168.     if (plsc->status == AT_BOP)
  169.     return;
  170.  
  171.     plsc->status = AT_BOP;
  172.  
  173.     offset = plsc->device - 1;
  174.     (*dispatch_table[offset].pl_bop) (plsc);
  175.  
  176.     if (plsc->plbuf_write)
  177.     plbuf_bop(plsc);
  178. }
  179.  
  180. /* Tidy up device (flush buffers, close file, etc.) */
  181.  
  182. void
  183. plP_tidy(void)
  184. {
  185.     if (plsc->tidy) {
  186.     (*plsc->tidy) (plsc->tidy_data);
  187.     plsc->tidy = NULL;
  188.     plsc->tidy_data = NULL;
  189.     }
  190.  
  191.     offset = plsc->device - 1;
  192.     (*dispatch_table[offset].pl_tidy) (plsc);
  193.  
  194.     if (plsc->plbuf_write)
  195.     plbuf_tidy(plsc);
  196.  
  197.     plsc->OutFile = NULL;
  198.     free_mem(plsc->FileName);
  199. }
  200.  
  201. /* Change state. */
  202.  
  203. void
  204. plP_state(PLINT op)
  205. {
  206.     offset = plsc->device - 1;
  207.     (*dispatch_table[offset].pl_state) (plsc, op);
  208.  
  209.     if (plsc->plbuf_write)
  210.     plbuf_state(plsc, op);
  211. }
  212.  
  213. /* Escape function, for driver-specific commands. */
  214.  
  215. void
  216. plP_esc(PLINT op, void *ptr)
  217. {
  218.     offset = plsc->device - 1;
  219.     (*dispatch_table[offset].pl_esc) (plsc, op, ptr);
  220.  
  221.     if (plsc->plbuf_write)
  222.     plbuf_esc(plsc, op, ptr);
  223. }
  224.  
  225. /*----------------------------------------------------------------------*\
  226.  *  Drawing commands.
  227. \*----------------------------------------------------------------------*/
  228.  
  229. /* Draw line between two points */
  230. /* The plot buffer must be called first so it gets the unfiltered data */
  231.  
  232. void
  233. plP_line(short *x, short *y)
  234. {
  235.     PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
  236.  
  237.     plsc->status = DRAWING;
  238.  
  239.     if (plsc->plbuf_write)
  240.     plbuf_line(plsc, x[0], y[0], x[1], y[1]);
  241.  
  242.     if (plsc->difilt) {
  243.     for (i = 0; i < npts; i++) {
  244.         xscl[i] = x[i];
  245.         yscl[i] = y[i];
  246.     }
  247.     difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  248.     plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
  249.     }
  250.     else {
  251.     grline(x, y, npts);
  252.     }
  253. }
  254.  
  255. /* Draw polyline */
  256. /* The plot buffer must be called first */
  257.  
  258. void
  259. plP_polyline(short *x, short *y, PLINT npts)
  260. {
  261.     PLINT i, clpxmi, clpxma, clpymi, clpyma;
  262.  
  263.     plsc->status = DRAWING;
  264.  
  265.     if (plsc->plbuf_write)
  266.     plbuf_polyline(plsc, x, y, npts);
  267.  
  268.     if (plsc->difilt) {
  269.     for (i = 0; i < npts; i++) {
  270.         xscl[i] = x[i];
  271.         yscl[i] = y[i];
  272.     }
  273.     difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  274.     plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  275.            grpolyline);
  276.     }
  277.     else {
  278.     grpolyline(x, y, npts);
  279.     }
  280. }
  281.  
  282. /* Fill polygon */
  283. /* The plot buffer must be called first */
  284.  
  285. void
  286. plP_fill(short *x, short *y, PLINT npts)
  287. {
  288.     PLINT i, clpxmi, clpxma, clpymi, clpyma;
  289.  
  290.     plsc->status = DRAWING;
  291.  
  292.     if (plsc->plbuf_write) {
  293.     plsc->dev_npts = npts;
  294.     plsc->dev_x = x;
  295.     plsc->dev_y = y;
  296.     plbuf_esc(plsc, PLESC_FILL, NULL);
  297.     }
  298.  
  299.     if (plsc->difilt) {
  300.     for (i = 0; i < npts; i++) {
  301.         xscl[i] = x[i];
  302.         yscl[i] = y[i];
  303.     }
  304.     difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  305.     plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  306.            grfill);
  307.     }
  308.     else {
  309.     grfill(x, y, npts);
  310.     }
  311. }
  312.  
  313. static void
  314. grline(short *x, short *y, PLINT npts)
  315. {
  316.     offset = plsc->device - 1;
  317.     (*dispatch_table[offset].pl_line) (plsc, x[0], y[0], x[1], y[1]);
  318. }
  319.  
  320. static void
  321. grpolyline(short *x, short *y, PLINT npts)
  322. {
  323.     offset = plsc->device - 1;
  324.     (*dispatch_table[offset].pl_polyline) (plsc, x, y, npts);
  325. }
  326.  
  327. /* Here if the desired area fill capability isn't present, we mock up */
  328. /* something in software */
  329.  
  330. static int foo;
  331.  
  332. static void
  333. grfill(short *x, short *y, PLINT npts)
  334. {
  335.     if (plsc->patt == 0 && ! plsc->dev_fill0) {
  336.     if ( ! foo) {
  337.         plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
  338.         foo = 1;
  339.     }
  340.     plsc->patt = 8;
  341.     plpsty(plsc->patt);
  342.     }
  343.     if (plsc->patt < 0 && ! plsc->dev_fill1) {
  344.     if ( ! foo) {
  345.         plwarn("Driver does not support hardware pattern fills, switching to software fill.\n");
  346.         foo = 1;
  347.     }
  348.     plsc->patt = ABS(plsc->patt) % 8 + 1;
  349.     plpsty(plsc->patt);
  350.     }
  351.  
  352.     if (plsc->patt <= 0) {
  353.     plsc->dev_npts = npts;
  354.     plsc->dev_x = x;
  355.     plsc->dev_y = y;
  356.  
  357.     offset = plsc->device - 1;
  358.     (*dispatch_table[offset].pl_esc) (plsc, PLESC_FILL, NULL);
  359.     }
  360.     else
  361.     plfill_soft(x, y, npts);
  362. }
  363.  
  364. /*----------------------------------------------------------------------*\
  365.  * void difilt
  366.  *
  367.  * Driver interface filter -- passes all coordinates through a variety
  368.  * of filters.  These include filters to change :
  369.  *
  370.  *    - mapping of meta to physical coordinates
  371.  *    - plot orientation
  372.  *    - window into plot (zooms)
  373.  *    - window into device (i.e set margins)
  374.  *
  375.  * The filters are applied in the order specified above.  Because the
  376.  * orientation change comes first, subsequent window specifications affect
  377.  * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
  378.  * This is the only way that makes sense from a graphical interface
  379.  * (e.g. TCL/TK driver).
  380.  *
  381.  * Where appropriate, the page clip limits are modified.
  382. \*----------------------------------------------------------------------*/
  383.  
  384. static void
  385. difilt(PLINT *xscl, PLINT *yscl, PLINT npts,
  386.        PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
  387. {
  388.     PLINT i, x, y;
  389.  
  390. /* Map meta coordinates to physical coordinates */
  391.  
  392.     if (plsc->difilt & PLDI_MAP) {
  393.     for (i = 0; i < npts; i++) {
  394.         xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
  395.         yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
  396.     }
  397.     }
  398.  
  399. /* Change orientation */
  400.  
  401.     if (plsc->difilt & PLDI_ORI) {
  402.     for (i = 0; i < npts; i++) {
  403.         x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
  404.         y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
  405.         xscl[i] = x;
  406.         yscl[i] = y;
  407.     }
  408.     }
  409.  
  410. /* Change window into plot space */
  411.  
  412.     if (plsc->difilt & PLDI_PLT) {
  413.     for (i = 0; i < npts; i++) {
  414.         xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
  415.         yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
  416.     }
  417.     }
  418.  
  419. /* Change window into device space and set clip limits */
  420. /* (this is the only filter that modifies them) */
  421.  
  422.     if (plsc->difilt & PLDI_DEV) {
  423.     for (i = 0; i < npts; i++) {
  424.         xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
  425.         yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
  426.     }
  427.     *clpxmi = plsc->diclpxmi;
  428.     *clpxma = plsc->diclpxma;
  429.     *clpymi = plsc->diclpymi;
  430.     *clpyma = plsc->diclpyma;
  431.     }
  432.     else {
  433.     *clpxmi = plsc->phyxmi;
  434.     *clpxma = plsc->phyxma;
  435.     *clpymi = plsc->phyymi;
  436.     *clpyma = plsc->phyyma;
  437.     }
  438. }
  439.  
  440. /*----------------------------------------------------------------------*\
  441.  * void pldi_ini
  442.  *
  443.  * Updates driver interface, making sure everything is in order.
  444.  * Even if filter is not being used, the defaults need to be set up.
  445. \*----------------------------------------------------------------------*/
  446.  
  447. static void
  448. setdef_diplt()
  449. {
  450.     plsc->dipxmin = 0.0;
  451.     plsc->dipxmax = 1.0;
  452.     plsc->dipymin = 0.0;
  453.     plsc->dipymax = 1.0;
  454. }
  455.  
  456. static void
  457. setdef_didev()
  458. {
  459.     plsc->mar = 0.0;
  460.     plsc->aspect = 0.0;
  461.     plsc->jx = 0.0;
  462.     plsc->jy = 0.0;
  463. }
  464.  
  465. static void
  466. setdef_diori()
  467. {
  468.     plsc->diorot = 0.;
  469. }
  470.  
  471. static void
  472. pldi_ini(void)
  473. {
  474.     if (plsc->level >= 1) {
  475.     if (plsc->difilt & PLDI_MAP)    /* Coordinate mapping */
  476.         calc_dimap();
  477.  
  478.     if (plsc->difilt & PLDI_ORI)    /* Orientation */
  479.         calc_diori();
  480.     else
  481.         setdef_diori();
  482.  
  483.     if (plsc->difilt & PLDI_PLT)     /* Plot window */
  484.         calc_diplt();
  485.     else
  486.         setdef_diplt();
  487.  
  488.     if (plsc->difilt & PLDI_DEV)    /* Device window */
  489.         calc_didev();
  490.     else
  491.         setdef_didev();
  492.     }
  493. }
  494.  
  495. /*----------------------------------------------------------------------*\
  496.  * void pldid2pc
  497.  *
  498.  * Converts input values from relative device coordinates to relative plot
  499.  * coordinates.  This function must be called when selecting a plot window
  500.  * from a display driver, since the coordinates chosen by the user are
  501.  * necessarily device-specific.
  502. \*----------------------------------------------------------------------*/
  503.  
  504. void
  505. pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  506. {
  507.     PLFLT pxmin, pymin, pxmax, pymax;
  508.     PLFLT sxmin, symin, sxmax, symax;
  509.     PLFLT rxmin, rymin, rxmax, rymax;
  510.  
  511. #ifdef DEBUG
  512.     fprintf(stderr, "Relative device coordinates (input): %f, %f, %f, %f\n",
  513.         *xmin, *ymin, *xmax, *ymax);
  514. #endif
  515.  
  516.     if (plsc->difilt & PLDI_DEV) {
  517.  
  518.     pxmin = plsc->phyxmi + (plsc->phyxma - plsc->phyxmi) * *xmin;
  519.     pymin = plsc->phyymi + (plsc->phyyma - plsc->phyymi) * *ymin;
  520.     pxmax = plsc->phyxmi + (plsc->phyxma - plsc->phyxmi) * *xmax;
  521.     pymax = plsc->phyymi + (plsc->phyyma - plsc->phyymi) * *ymax;
  522.  
  523.     sxmin = (pxmin - plsc->didxb) / plsc->didxax;
  524.     symin = (pymin - plsc->didyb) / plsc->didyay;
  525.     sxmax = (pxmax - plsc->didxb) / plsc->didxax;
  526.     symax = (pymax - plsc->didyb) / plsc->didyay;
  527.  
  528.     rxmin = (sxmin - plsc->phyxmi) / (plsc->phyxma - plsc->phyxmi);
  529.     rymin = (symin - plsc->phyymi) / (plsc->phyyma - plsc->phyymi);
  530.     rxmax = (sxmax - plsc->phyxmi) / (plsc->phyxma - plsc->phyxmi);
  531.     rymax = (symax - plsc->phyymi) / (plsc->phyyma - plsc->phyymi);
  532.  
  533.     *xmin = (rxmin < 0) ? 0 : rxmin;
  534.     *xmax = (rxmax > 1) ? 1 : rxmax;
  535.     *ymin = (rymin < 0) ? 0 : rymin;
  536.     *ymax = (rymax > 1) ? 1 : rymax;
  537.     }
  538.  
  539. #ifdef DEBUG
  540.     fprintf(stderr, "Relative plot coordinates (output): %f, %f, %f, %f\n",
  541.         rxmin, rymin, rxmax, rymax);
  542. #endif
  543. }
  544.  
  545. /*----------------------------------------------------------------------*\
  546.  * void pldip2dc
  547.  *
  548.  * Converts input values from relative plot coordinates to relative
  549.  * device coordinates.
  550. \*----------------------------------------------------------------------*/
  551.  
  552. void
  553. pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  554. {
  555.     PLFLT pxmin, pymin, pxmax, pymax;
  556.     PLFLT sxmin, symin, sxmax, symax;
  557.     PLFLT rxmin, rymin, rxmax, rymax;
  558.  
  559. #ifdef DEBUG
  560.     fprintf(stderr, "Relative plot coordinates (input): %f, %f, %f, %f\n",
  561.         *xmin, *ymin, *xmax, *ymax);
  562. #endif
  563.  
  564.     if (plsc->difilt & PLDI_DEV) {
  565.  
  566.     pxmin = plsc->phyxmi + (plsc->phyxma - plsc->phyxmi) * *xmin;
  567.     pymin = plsc->phyymi + (plsc->phyyma - plsc->phyymi) * *ymin;
  568.     pxmax = plsc->phyxmi + (plsc->phyxma - plsc->phyxmi) * *xmax;
  569.     pymax = plsc->phyymi + (plsc->phyyma - plsc->phyymi) * *ymax;
  570.  
  571.     sxmin = pxmin * plsc->didxax + plsc->didxb;
  572.     symin = pymin * plsc->didyay + plsc->didyb;
  573.     sxmax = pxmax * plsc->didxax + plsc->didxb;
  574.     symax = pymax * plsc->didyay + plsc->didyb;
  575.  
  576.     rxmin = (sxmin - plsc->phyxmi) / (plsc->phyxma - plsc->phyxmi);
  577.     rymin = (symin - plsc->phyymi) / (plsc->phyyma - plsc->phyymi);
  578.     rxmax = (sxmax - plsc->phyxmi) / (plsc->phyxma - plsc->phyxmi);
  579.     rymax = (symax - plsc->phyymi) / (plsc->phyyma - plsc->phyymi);
  580.  
  581.     *xmin = (rxmin < 0) ? 0 : rxmin;
  582.     *xmax = (rxmax > 1) ? 1 : rxmax;
  583.     *ymin = (rymin < 0) ? 0 : rymin;
  584.     *ymax = (rymax > 1) ? 1 : rymax;
  585.     }
  586.  
  587. #ifdef DEBUG
  588.     fprintf(stderr, "Relative device coordinates (output): %f, %f, %f, %f\n",
  589.         rxmin, rymin, rxmax, rymax);
  590. #endif
  591. }
  592.  
  593. /*----------------------------------------------------------------------*\
  594.  * void plsdiplt
  595.  *
  596.  * Set window into plot space
  597. \*----------------------------------------------------------------------*/
  598.  
  599. void
  600. c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  601. {
  602.     plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
  603.     plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
  604.     plsc->dipymin = (ymin < ymax) ? ymin : ymax;
  605.     plsc->dipymax = (ymin < ymax) ? ymax : ymin;
  606.  
  607.     if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.)  {
  608.     plsc->difilt &= ~PLDI_PLT;
  609.     return;
  610.     }
  611.  
  612.     plsc->difilt |= PLDI_PLT;
  613.     pldi_ini();
  614. }
  615.  
  616. /*----------------------------------------------------------------------*\
  617.  * void plsdiplz
  618.  *
  619.  * Set window into plot space incrementally (zoom)
  620. \*----------------------------------------------------------------------*/
  621.  
  622. void
  623. c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  624. {
  625.     if (plsc->difilt & PLDI_PLT) {
  626.     xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
  627.     ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
  628.     xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
  629.     ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
  630.     }
  631.  
  632.     plsdiplt(xmin, ymin, xmax, ymax);
  633. }
  634.  
  635. /*----------------------------------------------------------------------*\
  636.  * void calc_diplt
  637.  *
  638.  * Calculate transformation coefficients to set window into plot space.
  639.  *
  640.  * Note: if driver has requested to handle these commands itself, we must
  641.  * send the appropriate escape command.  If the driver succeeds it will
  642.  * cancel the filter operation.  The command is deferred until this point
  643.  * to ensure that the driver has been initialized.
  644. \*----------------------------------------------------------------------*/
  645.  
  646. static void
  647. calc_diplt(void)
  648. {
  649.     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  650.  
  651.     if (plsc->dev_di) {
  652.     offset = plsc->device - 1;
  653.     (*dispatch_table[offset].pl_esc) (plsc, PLESC_DI, NULL);
  654.     }
  655.  
  656.     if ( ! (plsc->difilt & PLDI_PLT))
  657.     return;
  658.  
  659.     pxmin = plsc->dipxmin * (plsc->phyxma - plsc->phyxmi) + plsc->phyxmi;
  660.     pxmax = plsc->dipxmax * (plsc->phyxma - plsc->phyxmi) + plsc->phyxmi;
  661.     pymin = plsc->dipymin * (plsc->phyyma - plsc->phyymi) + plsc->phyymi;
  662.     pymax = plsc->dipymax * (plsc->phyyma - plsc->phyymi) + plsc->phyymi;
  663.  
  664.     pxlen = pxmax - pxmin;
  665.     pylen = pymax - pymin;
  666.     pxlen = MAX(1, pxlen);
  667.     pylen = MAX(1, pylen);
  668.  
  669.     plsc->dipxax = (float) (plsc->phyxma - plsc->phyxmi) / (float) pxlen;
  670.     plsc->dipyay = (float) (plsc->phyyma - plsc->phyymi) / (float) pylen;
  671.     plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
  672.     plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
  673. }
  674.  
  675. /*----------------------------------------------------------------------*\
  676.  * void plgdiplt
  677.  *
  678.  * Retrieve current window into plot space
  679. \*----------------------------------------------------------------------*/
  680.  
  681. void
  682. c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
  683. {
  684.     *p_xmin = plsc->dipxmin;
  685.     *p_xmax = plsc->dipxmax;
  686.     *p_ymin = plsc->dipymin;
  687.     *p_ymax = plsc->dipymax;
  688. }
  689.  
  690. /*----------------------------------------------------------------------*\
  691.  * void plsdidev
  692.  *
  693.  * Set window into device space using margin, aspect ratio, and
  694.  * justification.  If you want to just use the previous value for any of
  695.  * these, just pass in the magic value PL_NOTSET.
  696.  *
  697.  * It is unlikely that one should ever need to change the aspect ratio
  698.  * but it's in there for completeness.
  699. \*----------------------------------------------------------------------*/
  700.  
  701. void
  702. c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
  703. {
  704.     plsetvar(plsc->mar, mar);
  705.     plsetvar(plsc->aspect, aspect);
  706.     plsetvar(plsc->jx, jx);
  707.     plsetvar(plsc->jy, jy);
  708.  
  709.     if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
  710.     ! (plsc->difilt & PLDI_ORI)) {
  711.     plsc->difilt &= ~PLDI_DEV;
  712.     return;
  713.     }
  714.  
  715.     plsc->difilt |= PLDI_DEV;
  716.     pldi_ini();
  717. }
  718.  
  719. /*----------------------------------------------------------------------*\
  720.  * void calc_didev
  721.  *
  722.  * Calculate transformation coefficients to set window into device space.
  723.  * Calculates relative window bounds and calls plsdidxy to finish the job.
  724. \*----------------------------------------------------------------------*/
  725.  
  726. static void
  727. calc_didev(void)
  728. {
  729.     PLFLT lx, ly, aspect, aspdev;
  730.     PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
  731.     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  732.  
  733.     if (plsc->dev_di) {
  734.     offset = plsc->device - 1;
  735.     (*dispatch_table[offset].pl_esc) (plsc, PLESC_DI, NULL);
  736.     }
  737.  
  738.     if ( ! (plsc->difilt & PLDI_DEV))
  739.     return;
  740.  
  741. /* Calculate aspect ratio of physical device */
  742.  
  743.     lx = (plsc->phyxma - plsc->phyxmi + 1) / plsc->xpmm;
  744.     ly = (plsc->phyyma - plsc->phyymi + 1) / plsc->ypmm;
  745.     aspdev = lx / ly;
  746.  
  747.     if (plsc->difilt & PLDI_ORI)
  748.     aspect = plsc->aspori;
  749.     else
  750.     aspect = plsc->aspect;
  751.  
  752.     if (aspect <= 0.)
  753.     aspect = plsc->aspdev;
  754.  
  755. /* Failsafe */
  756.  
  757.     plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
  758.     plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
  759.     plsc->jx = (plsc->jx >  0.5) ?  0.5 : plsc->jx;
  760.     plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
  761.     plsc->jy = (plsc->jy >  0.5) ?  0.5 : plsc->jy;
  762.     plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
  763.  
  764. /* Relative device coordinates that neutralize aspect ratio difference */
  765.  
  766.     xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
  767.     ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
  768.  
  769.     xlen *= (1.0 - 2.*plsc->mar);
  770.     ylen *= (1.0 - 2.*plsc->mar);
  771.  
  772.     xmin = (1. - xlen) * (0.5 + plsc->jx);
  773.     xmax = xmin + xlen;
  774.  
  775.     ymin = (1. - ylen) * (0.5 + plsc->jy);
  776.     ymax = ymin + ylen;
  777.  
  778. /* Calculate transformation coefficients */
  779.  
  780.     pxmin = xmin * (plsc->phyxma - plsc->phyxmi) + plsc->phyxmi;
  781.     pxmax = xmax * (plsc->phyxma - plsc->phyxmi) + plsc->phyxmi;
  782.     pymin = ymin * (plsc->phyyma - plsc->phyymi) + plsc->phyymi;
  783.     pymax = ymax * (plsc->phyyma - plsc->phyymi) + plsc->phyymi;
  784.  
  785.     pxlen = pxmax - pxmin;
  786.     pylen = pymax - pymin;
  787.     pxlen = MAX(1, pxlen);
  788.     pylen = MAX(1, pylen);
  789.  
  790.     plsc->didxax = (float) pxlen / (float) (plsc->phyxma - plsc->phyxmi);
  791.     plsc->didyay = (float) pylen / (float) (plsc->phyyma - plsc->phyymi);
  792.     plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
  793.     plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
  794.  
  795. /* Set clip limits to conform to new page size */
  796.  
  797.     plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
  798.     plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
  799.     plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
  800.     plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
  801. }
  802.  
  803. /*----------------------------------------------------------------------*\
  804.  * void plgdidev
  805.  *
  806.  * Retrieve current window into device space
  807. \*----------------------------------------------------------------------*/
  808.  
  809. void
  810. c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
  811. {
  812.     *p_mar = plsc->mar;
  813.     *p_aspect = plsc->aspect;
  814.     *p_jx = plsc->jx;
  815.     *p_jy = plsc->jy;
  816. }
  817.  
  818. /*----------------------------------------------------------------------*\
  819.  * void plsdiori
  820.  *
  821.  * Set plot orientation, specifying rotation in units of pi/2.
  822. \*----------------------------------------------------------------------*/
  823.  
  824. void
  825. c_plsdiori(PLFLT rot)
  826. {
  827.     plsc->diorot = rot;
  828.     if (rot == 0.) {
  829.     plsc->difilt &= ~PLDI_ORI;
  830.     pldi_ini();
  831.     return;
  832.     }
  833.  
  834.     plsc->difilt |= PLDI_ORI;
  835.     pldi_ini();
  836. }
  837.  
  838. /*----------------------------------------------------------------------*\
  839.  * void calc_diori
  840.  *
  841.  * Calculate transformation coefficients to arbitrarily orient plot.
  842.  * Preserve aspect ratios so the output doesn't suck.
  843. \*----------------------------------------------------------------------*/
  844.  
  845. static void
  846. calc_diori(void)
  847. {
  848.     PLFLT r11, r21, r12, r22, cost, sint;
  849.     PLFLT x0, y0, lx, ly, aspect;
  850.  
  851.     if (plsc->dev_di) {
  852.     offset = plsc->device - 1;
  853.     (*dispatch_table[offset].pl_esc) (plsc, PLESC_DI, NULL);
  854.     }
  855.  
  856.     if ( ! (plsc->difilt & PLDI_ORI))
  857.     return;
  858.  
  859. /* Center point of rotation */
  860.  
  861.     x0 = (plsc->phyxma + plsc->phyxmi) / 2.;
  862.     y0 = (plsc->phyyma + plsc->phyymi) / 2.;
  863.  
  864. /* Rotation matrix */
  865.  
  866.     r11 = cos(plsc->diorot * PI / 2.);
  867.     r21 = sin(plsc->diorot * PI / 2.);
  868.     r12 = -r21;
  869.     r22 = r11;
  870.  
  871.     cost = ABS(r11);
  872.     sint = ABS(r21);
  873.  
  874. /* Flip aspect ratio as necessary.  Grungy but I don't see a better way */
  875.  
  876.     aspect = plsc->aspect;
  877.     if (aspect == 0.)
  878.     aspect = plsc->aspdev;
  879.  
  880.     plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
  881.  
  882.     if ( ! (plsc->difilt & PLDI_DEV)) {
  883.     plsc->difilt |= PLDI_DEV;
  884.     setdef_didev();
  885.     }
  886.     calc_didev();
  887.  
  888. /* Compute scale factors */
  889.  
  890.     lx = plsc->phyxma - plsc->phyxmi;
  891.     ly = plsc->phyyma - plsc->phyymi;
  892.  
  893. /* Transformation coefficients */
  894.  
  895.     plsc->dioxax = r11;
  896.     plsc->dioxay = r21 * (lx / ly);
  897.     plsc->dioxb = (1. - r11) * x0 - r21 * y0 * (lx / ly);
  898.  
  899.     plsc->dioyax = r12 * (ly / lx);
  900.     plsc->dioyay = r22;
  901.     plsc->dioyb = (1. - r22) * y0 - r12 * x0 * (ly / lx);
  902. }
  903.  
  904. /*----------------------------------------------------------------------*\
  905.  * void plgdiori
  906.  *
  907.  * Get plot orientation
  908. \*----------------------------------------------------------------------*/
  909.  
  910. void
  911. c_plgdiori(PLFLT *p_rot)
  912. {
  913.     *p_rot = plsc->diorot;
  914. }
  915.  
  916. /*----------------------------------------------------------------------*\
  917.  * void plsdimap
  918.  *
  919.  * Set up transformation from metafile coordinates.
  920.  * The size of the plot is scaled so as to preserve aspect ratio.
  921.  * This isn't intended to be a general-purpose facility just yet
  922.  * (not sure why the user would need it, for one).
  923. \*----------------------------------------------------------------------*/
  924.  
  925. void
  926. c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
  927.        PLFLT dimxpmm, PLFLT dimypmm)
  928. {
  929.     plsetvar(plsc->dimxmin, dimxmin);
  930.     plsetvar(plsc->dimxmax, dimxmax);
  931.     plsetvar(plsc->dimymin, dimymin);
  932.     plsetvar(plsc->dimymax, dimymax);
  933.     plsetvar(plsc->dimxpmm, dimxpmm);
  934.     plsetvar(plsc->dimypmm, dimypmm);
  935.  
  936.     plsc->difilt |= PLDI_MAP;
  937.     pldi_ini();
  938. }
  939.  
  940. /*----------------------------------------------------------------------*\
  941.  * void calc_dimap
  942.  *
  943.  * Set up transformation from metafile coordinates.  The size of the plot
  944.  * is scaled so as to preserve aspect ratio.  This isn't intended to be a
  945.  * general-purpose facility just yet (not sure why the user would need it,
  946.  * for one).
  947. \*----------------------------------------------------------------------*/
  948.  
  949. static void
  950. calc_dimap()
  951. {
  952.     PLFLT lx, ly;
  953.     PLINT pxmin, pxmax, pymin, pymax;
  954.     PLFLT dimxlen, dimylen, pxlen, pylen;
  955.  
  956.     if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
  957.     (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
  958.     (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
  959.     plsc->difilt &= ~PLDI_MAP;
  960.     return;
  961.     }
  962.  
  963. /* Set default aspect ratio */
  964.  
  965.     lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
  966.     ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
  967.  
  968.     plsc->aspdev = lx / ly;
  969.  
  970. /* Build transformation to correct physical coordinates */
  971.  
  972.     dimxlen = plsc->dimxmax - plsc->dimxmin;
  973.     dimylen = plsc->dimymax - plsc->dimymin;
  974.  
  975.     pxmin = plsc->phyxmi;
  976.     pxmax = plsc->phyxma;
  977.     pymin = plsc->phyymi;
  978.     pymax = plsc->phyyma;
  979.     pxlen = pxmax - pxmin;
  980.     pylen = pymax - pymin;
  981.  
  982.     plsc->dimxax = pxlen / dimxlen;
  983.     plsc->dimyay = pylen / dimylen;
  984.     plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
  985.     plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
  986. }
  987.  
  988. /*----------------------------------------------------------------------*\
  989.  * void plflush()
  990.  *
  991.  * Flushes the output stream.  Use sparingly, if at all.
  992. \*----------------------------------------------------------------------*/
  993.  
  994. void
  995. c_plflush(void)
  996. {
  997.     if (plsc->dev_flush) {
  998.     offset = plsc->device - 1;
  999.     (*dispatch_table[offset].pl_esc) (plsc, PLESC_FLUSH, NULL);
  1000.     }
  1001.     else {
  1002.     if (plsc->OutFile != NULL)
  1003.         fflush(plsc->OutFile);
  1004.     }
  1005. }
  1006.  
  1007. /*----------------------------------------------------------------------*\
  1008.  * Startup routines.
  1009. \*----------------------------------------------------------------------*/
  1010.  
  1011. /*----------------------------------------------------------------------*\
  1012.  * void plstar(nx, ny)
  1013.  *
  1014.  * Initialize plplot, passing in the windows/page settings.
  1015. \*----------------------------------------------------------------------*/
  1016.  
  1017. void
  1018. c_plstar(PLINT nx, PLINT ny)
  1019. {
  1020.     if (plsc->level != 0)
  1021.     plend1();
  1022.  
  1023.     plssub(nx, ny);
  1024.  
  1025.     c_plinit();
  1026. }
  1027.  
  1028. /*----------------------------------------------------------------------*\
  1029.  * void plstart(devname, nx, ny)
  1030.  *
  1031.  * Initialize plplot, passing the device name and windows/page settings.
  1032. \*----------------------------------------------------------------------*/
  1033.  
  1034. void
  1035. c_plstart(const char *devname, PLINT nx, PLINT ny)
  1036. {
  1037.     if (plsc->level != 0)
  1038.     plend1();
  1039.  
  1040.     plssub(nx, ny);
  1041.     plsdev(devname);
  1042.  
  1043.     c_plinit();
  1044. }
  1045.  
  1046. /*----------------------------------------------------------------------*\
  1047.  * void plinit()
  1048.  *
  1049.  * Initializes plplot, using preset or default options.
  1050. \*----------------------------------------------------------------------*/
  1051.  
  1052. void
  1053. c_plinit(void)
  1054. {
  1055.     PLFLT lx, ly;
  1056.     PLINT mk = 0, sp = 0, inc = 0, del = 2000;
  1057.  
  1058.     if (plsc->level != 0)
  1059.     plend1();
  1060.  
  1061. /* Set device number */
  1062.  
  1063.     plGetDev();
  1064.  
  1065. /* Stream number */
  1066.  
  1067.     plsc->ipls = ipls;
  1068.  
  1069. /* Initialize color maps */
  1070.  
  1071.     plCmap0_init();
  1072.     plCmap1_init();
  1073.  
  1074. /* Load fonts */
  1075.  
  1076.     font = 1;
  1077.     if (fontset) {
  1078.     plfntld(initfont);
  1079.     fontset = 0;
  1080.     }
  1081.     else
  1082.     plfntld(0);
  1083.  
  1084. /* Initialize device & first page */
  1085.  
  1086.     plP_init();
  1087.     plsc->level = 1;
  1088.  
  1089.     plP_bop();
  1090.  
  1091. /* Set up subpages */
  1092.  
  1093.     plP_subpInit();
  1094.  
  1095. /* Set up number of allowed digits before switching to scientific notation */
  1096. /* The user can always change this */
  1097.  
  1098.     if (plsc->xdigmax == 0)
  1099.     plsc->xdigmax = 4;
  1100.  
  1101.     if (plsc->ydigmax == 0)
  1102.     plsc->ydigmax = 4;
  1103.  
  1104.     if (plsc->zdigmax == 0)
  1105.     plsc->zdigmax = 3;
  1106.  
  1107. /* Switch to graphics mode and set color */
  1108.  
  1109.     plgra();
  1110.     plcol(1);
  1111.  
  1112.     plstyl(0, &mk, &sp);
  1113.     plpat(1, &inc, &del);
  1114.  
  1115. /* Set clip limits. */
  1116.  
  1117.     plsc->clpxmi = plsc->phyxmi;
  1118.     plsc->clpxma = plsc->phyxma;
  1119.     plsc->clpymi = plsc->phyymi;
  1120.     plsc->clpyma = plsc->phyyma;
  1121.  
  1122. /* Page aspect ratio. */
  1123.  
  1124.     lx = (plsc->phyxma - plsc->phyxmi) / plsc->xpmm;
  1125.     ly = (plsc->phyyma - plsc->phyymi) / plsc->ypmm;
  1126.     plsc->aspdev = lx / ly;
  1127.  
  1128. /* Initialize driver interface */
  1129.  
  1130.     pldi_ini();
  1131. }
  1132.  
  1133. /*----------------------------------------------------------------------*\
  1134.  * void plend()
  1135.  *
  1136.  * End a plotting session for all open streams.
  1137. \*----------------------------------------------------------------------*/
  1138.  
  1139. void
  1140. c_plend(void)
  1141. {
  1142.     PLINT i;
  1143.  
  1144.     for (i = PL_NSTREAMS-1; i >= 0; i--) {
  1145.     if (pls[i] != NULL) {
  1146.         plsstrm(i);
  1147.         c_plend1();
  1148.     }
  1149.     }
  1150.     plfontrel();
  1151. }
  1152.  
  1153. /*----------------------------------------------------------------------*\
  1154.  * void plend1()
  1155.  *
  1156.  * End a plotting session for the current stream only.  After the stream
  1157.  * is ended the memory associated with the stream's PLStream data
  1158.  * structure is freed (for stream > 0), and the stream counter is set to 0
  1159.  * (the default).
  1160. \*----------------------------------------------------------------------*/
  1161.  
  1162. void
  1163. c_plend1(void)
  1164. {
  1165.     if (plsc->level > 0) {
  1166.     plsc->level = 0;
  1167.     plP_eop();
  1168.     plP_tidy();
  1169.     }
  1170. #ifdef __riscos
  1171.     plsc->famadv = 0;
  1172.     plsc->page = 0;
  1173.     plsc->member = 0;
  1174. #endif
  1175.  
  1176. /* Free all malloc'ed stream memory */
  1177.  
  1178.     free_mem(plsc->plwindow);
  1179.     free_mem(plsc->geometry);
  1180.     free_mem(plsc->dev);
  1181.     free_mem(plsc->BaseName);
  1182.  
  1183. /* Free malloc'ed stream if not in initial stream */
  1184.  
  1185.     if (ipls > 0) {
  1186.     free_mem(plsc);
  1187.     pls[ipls] = NULL;
  1188.     plsstrm(0);
  1189.     }
  1190. }
  1191.  
  1192. /*----------------------------------------------------------------------*\
  1193.  * void plsstrm
  1194.  *
  1195.  * Set stream number.  If the data structure for a new stream is
  1196.  * unallocated, we allocate it here.
  1197. \*----------------------------------------------------------------------*/
  1198.  
  1199. void
  1200. c_plsstrm(PLINT strm)
  1201. {
  1202.     if (strm < 0 || strm >= PL_NSTREAMS) {
  1203.     fprintf(stderr,
  1204.         "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
  1205.         (int) strm, PL_NSTREAMS);
  1206.     }
  1207.     else {
  1208.     ipls = strm;
  1209.     if (pls[ipls] == NULL) {
  1210.         pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
  1211.         if (pls[ipls] == NULL)
  1212.         plexit("plsstrm: Out of memory.");
  1213.  
  1214.         memset((char *) pls[ipls], 0, sizeof(PLStream));
  1215.     }
  1216.     plsc = pls[ipls];
  1217.     }
  1218. }
  1219.  
  1220. /*----------------------------------------------------------------------*\
  1221.  * void plgstrm
  1222.  *
  1223.  * Get current stream number.
  1224. \*----------------------------------------------------------------------*/
  1225.  
  1226. void
  1227. c_plgstrm(PLINT *p_strm)
  1228. {
  1229.     *p_strm = ipls;
  1230. }
  1231.  
  1232. /*----------------------------------------------------------------------*\
  1233.  * void plmkstrm
  1234.  *
  1235.  * Creates a new stream and makes it the default.  Differs from using
  1236.  * plsstrm(), in that a free stream number is found, and returned.
  1237.  *
  1238.  * Unfortunately, I /have/ to start at stream 1 and work upward, since
  1239.  * stream 0 is preallocated.  One of the BIG flaws in the PLplot API is
  1240.  * that no initial, library-opening call is required.  So stream 0 must be
  1241.  * preallocated, and there is no simple way of determining whether it is
  1242.  * already in use or not.
  1243. \*----------------------------------------------------------------------*/
  1244.  
  1245. void
  1246. c_plmkstrm(PLINT *p_strm)
  1247. {
  1248.     int i;
  1249.  
  1250.     for (i = 1; i < PL_NSTREAMS; i++) {
  1251.     if (pls[i] == NULL)
  1252.         break;
  1253.     }
  1254.  
  1255.     if (i == PL_NSTREAMS) {
  1256.     fprintf(stderr, "plmkstrm: Cannot create new stream\n");
  1257.     *p_strm = -1;
  1258.     }
  1259.     else {
  1260.     *p_strm = i;
  1261.     plsstrm(i);
  1262.     }
  1263. }
  1264.  
  1265. /*----------------------------------------------------------------------*\
  1266.  * void plcpstrm
  1267.  *
  1268.  * Copies state parameters from the reference stream to the current stream.
  1269.  * Tell driver interface to map device coordinates unless flags == 1.
  1270.  *
  1271.  * This function is used for making save files of selected plots (e.g.
  1272.  * from the TK driver).  After initializing, you can get a copy of the
  1273.  * current plot to the specified device by switching to this stream and
  1274.  * issuing a plcpstrm() and a plreplot(), with calls to plbop() and
  1275.  * pleop() as appropriate.  The plot buffer must have previously been
  1276.  * enabled (done automatically by some display drivers, such as X).
  1277. \*----------------------------------------------------------------------*/
  1278.  
  1279. static void
  1280. cp_color(PLColor *to, PLColor *from)
  1281. {
  1282.     to->r = from->r;
  1283.     to->g = from->g;
  1284.     to->b = from->b;
  1285. }
  1286.  
  1287. void
  1288. c_plcpstrm(PLINT iplsr, PLINT flags)
  1289. {
  1290.     int i;
  1291.     PLStream *plsr;
  1292.  
  1293.     plsr = pls[iplsr];
  1294.     if (plsr == NULL) {
  1295.     fprintf(stderr, "plcpstrm: stream %d not in use\n", (int) iplsr);
  1296.     return;
  1297.     }
  1298.  
  1299. /* Plot buffer -- need to copy file pointer so that plreplot() works */
  1300. /* This also prevents inadvertent writes into the plot buffer */
  1301.  
  1302.     plsc->plbufFile = plsr->plbufFile;
  1303.  
  1304. /* Driver interface */
  1305. /* Transformation must be recalculated in current driver coordinates */
  1306.  
  1307.     if (plsr->difilt & PLDI_PLT)
  1308.     plsdiplt(plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax);
  1309.  
  1310.     if (plsr->difilt & PLDI_DEV)
  1311.     plsdidev(plsr->mar, plsr->aspect, plsr->jx, plsr->jy);
  1312.  
  1313.     if (plsr->difilt & PLDI_ORI)
  1314.     plsdiori(plsr->diorot);
  1315.  
  1316. /* Map device coordinates */
  1317.  
  1318.     if ( ! (flags & 0x01))
  1319.     plsdimap(plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
  1320.          plsr->xpmm, plsr->ypmm);
  1321.  
  1322. /* Palettes */
  1323.  
  1324.     plsc->icol0 = plsr->icol0;
  1325.     plsc->ncol0 = plsr->ncol0;
  1326.     plsc->icol1 = plsr->icol1;
  1327.     plsc->ncol1 = plsr->ncol1;
  1328.  
  1329.     cp_color(&plsc->curcolor, &plsr->curcolor);
  1330.     for (i = 0; i < 16; i++) {
  1331.     plsc->cmap0setcol[i] = plsr->cmap0setcol[i];
  1332.     cp_color(&plsc->cmap0[i], &plsr->cmap0[i]);
  1333.     }
  1334.  
  1335.     plsc->cmap1set = plsr->cmap1set;
  1336.     for (i = 0; i < 256; i++) {
  1337.     cp_color(&plsc->cmap1[i], &plsr->cmap1[i]);
  1338.     }
  1339.  
  1340. /* Initialize if it hasn't been done yet. */
  1341.  
  1342.     if (plsc->level == 0)
  1343.     plinit();
  1344. }
  1345.  
  1346. /*----------------------------------------------------------------------*\
  1347.  * void plGetDev()
  1348.  *
  1349.  * If the the user has not already specified the output device, or the
  1350.  * one specified is either: (a) not available, (b) "?", or (c) NULL, the
  1351.  * user is prompted for it.
  1352.  *
  1353.  * Prompting quits after 10 unsuccessful tries in case the user has
  1354.  * run the program in the background with insufficient input.
  1355. \*----------------------------------------------------------------------*/
  1356.  
  1357. static void
  1358. plGetDev()
  1359. {
  1360.     PLINT dev, i, count, length;
  1361.     char response[80];
  1362.  
  1363. /* Device name already specified.  See if it is valid. */
  1364.  
  1365.     if (*(plsc->DevName) != '\0' && *(plsc->DevName) != '?') {
  1366.     length = strlen(plsc->DevName);
  1367.     for (i = 0; i < npldrivers; i++) {
  1368.         if ((*plsc->DevName == *dispatch_table[i].pl_DevName) &&
  1369.         (strncmp(plsc->DevName,
  1370.              dispatch_table[i].pl_DevName, length) == 0))
  1371.         break;
  1372.     }
  1373.     if (i < npldrivers) {
  1374.         plsc->device = i + 1;
  1375.         return;
  1376.     }
  1377.     else {
  1378.         printf("Requested device %s not available\n", plsc->DevName);
  1379.     }
  1380.     }
  1381.  
  1382.     dev = 0;
  1383.     count = 0;
  1384.  
  1385.     if (npldrivers == 1)
  1386.     dev = 1;
  1387.  
  1388. /* User hasn't specified it correctly yet, so we prompt */
  1389.  
  1390.     while (dev < 1 || dev > npldrivers) {
  1391.     printf("\nPlotting Options:\n");
  1392.     for (i = 0; i < npldrivers; i++) {
  1393.         printf(" <%2d> %-10s %s\n", i + 1, dispatch_table[i].pl_DevName,
  1394.            dispatch_table[i].pl_MenuStr);
  1395.     }
  1396.     if (ipls == 0)
  1397.         printf("\nEnter device number or keyword: ");
  1398.     else
  1399.         printf("\nEnter device number or keyword (stream %d): ",
  1400.            (int) ipls);
  1401.  
  1402.     fgets(response, sizeof(response), stdin);
  1403.  
  1404. /* First check to see if device keyword was entered. */
  1405. /* Final "\n" in response messes things up, so ignore it.  */
  1406.  
  1407.     length = strlen(response);
  1408.     if (*(response - 1 + length) == '\n')
  1409.         length--;
  1410.  
  1411.     for (i = 0; i < npldrivers; i++) {
  1412.         if (!strncmp(response, dispatch_table[i].pl_DevName,
  1413.              (unsigned int) length))
  1414.         break;
  1415.     }
  1416.     if (i < npldrivers) {
  1417.         dev = i + 1;
  1418.     }
  1419.     else {
  1420.         if ((dev = atoi(response)) < 1) {
  1421.         printf("Invalid device.");
  1422.         dev = 0;
  1423.         }
  1424.     }
  1425.     if (count++ > 10)
  1426.         plexit("plGetDev: Too many tries.");
  1427.     }
  1428.     plsc->device = dev;
  1429.     strcpy(plsc->DevName, dispatch_table[dev - 1].pl_DevName);
  1430. }
  1431.  
  1432. /*----------------------------------------------------------------------*\
  1433.  * void c_plfont(ifont)
  1434.  *
  1435.  * Sets the global font flag to 'ifont'.
  1436. \*----------------------------------------------------------------------*/
  1437.  
  1438. void
  1439. c_plfont(PLINT ifont)
  1440. {
  1441.     if (plsc->level < 1) {
  1442.     plabort("plfont: Please call plinit first");
  1443.     return;
  1444.     }
  1445.     if (ifont < 1 || ifont > 4) {
  1446.     plabort("plfont: Invalid font");
  1447.     return;
  1448.     }
  1449.  
  1450.     font = ifont;
  1451. }
  1452.  
  1453. /*----------------------------------------------------------------------*\
  1454.  * void plfontld()
  1455.  *
  1456.  * Load specified font set.
  1457. \*----------------------------------------------------------------------*/
  1458.  
  1459. void
  1460. c_plfontld(PLINT fnt)
  1461. {
  1462.     if (fnt != 0)
  1463.     fnt = 1;
  1464.  
  1465.     if (plsc->level > 0)
  1466.     plfntld(fnt);
  1467.     else {
  1468.     initfont = fnt;
  1469.     fontset = 1;
  1470.     }
  1471. }
  1472.  
  1473. /*----------------------------------------------------------------------*\
  1474.  * void plreplot()
  1475.  *
  1476.  * Replays contents of plot buffer to current device/file.
  1477. \*----------------------------------------------------------------------*/
  1478.  
  1479. void
  1480. c_plreplot(void)
  1481. {
  1482.     if (plsc->plbufFile != NULL) {
  1483.     plRemakePlot(plsc);
  1484.     }
  1485.     else {
  1486.     plwarn("plreplot: plot buffer not available");
  1487.     }
  1488. }
  1489.  
  1490. /*----------------------------------------------------------------------*\
  1491.  * void plgFileDevs()
  1492.  *
  1493.  * Returns a list of file-oriented device names and their menu strings,
  1494.  * for use in a graphical interface.  The caller must allocate enough
  1495.  * space for (*p_menustr) and (*p_devname) to hold a pointer for each
  1496.  * device -- 20 or so is plenty.  E.g. char *menustr[20].
  1497. \*----------------------------------------------------------------------*/
  1498.  
  1499. void
  1500. plgFileDevs(char ***p_menustr, char ***p_devname, int *p_ndev)
  1501. {
  1502.     int i, j;
  1503.  
  1504.     for (i = j = 0; i < npldrivers; i++) {
  1505.     if (dispatch_table[i].pl_type == 0) {
  1506.         (*p_menustr)[j] = dispatch_table[i].pl_MenuStr;
  1507.         (*p_devname)[j] = dispatch_table[i].pl_DevName;
  1508.         j++;
  1509.     }
  1510.     }
  1511.     (*p_menustr)[j] = NULL;
  1512.     (*p_devname)[j] = NULL;
  1513.     *p_ndev = j;
  1514. }
  1515.  
  1516. /*----------------------------------------------------------------------*\
  1517.  *  Various external access routines.
  1518. \*----------------------------------------------------------------------*/
  1519.  
  1520. /* Get output device parameters. */
  1521.  
  1522. void
  1523. c_plgpage(PLFLT *p_xp, PLFLT *p_yp,
  1524.       PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff)
  1525. {
  1526.     *p_xp = plsc->xdpi;
  1527.     *p_yp = plsc->ydpi;
  1528.     *p_xleng = plsc->xlength;
  1529.     *p_yleng = plsc->ylength;
  1530.     *p_xoff = plsc->xoffset;
  1531.     *p_yoff = plsc->yoffset;
  1532. }
  1533.  
  1534. /* Set output device parameters.  Usually ignored by the driver. */
  1535.  
  1536. void
  1537. c_plspage(PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff)
  1538. {
  1539.     if (xp)
  1540.     plsc->xdpi = xp;
  1541.     if (yp)
  1542.     plsc->ydpi = yp;
  1543.  
  1544.     if (xleng)
  1545.     plsc->xlength = xleng;
  1546.     if (yleng)
  1547.     plsc->ylength = yleng;
  1548.  
  1549.     if (xoff)
  1550.     plsc->xoffset = xoff;
  1551.     if (yoff)
  1552.     plsc->yoffset = yoff;
  1553.  
  1554.     plsc->pageset = 1;
  1555. }
  1556.  
  1557. /* Set the number of subwindows in x and y */
  1558.  
  1559. void
  1560. c_plssub(PLINT nx, PLINT ny)
  1561. {
  1562.     if (nx > 0)
  1563.     plsc->nsubx = nx;
  1564.     if (ny > 0)
  1565.     plsc->nsuby = ny;
  1566.  
  1567.     if (plsc->level > 0)
  1568.     plP_subpInit();
  1569. }
  1570.  
  1571. /* Set the device (keyword) name */
  1572.  
  1573. void
  1574. c_plsdev(const char *devname)
  1575. {
  1576.     if (plsc->level > 0) {
  1577.     plwarn("plsdev: Must be called before plinit.");
  1578.     return;
  1579.     }
  1580.     if (devname != NULL) {
  1581.     strncpy(plsc->DevName, devname, sizeof(plsc->DevName) - 1);
  1582.     plsc->DevName[sizeof(plsc->DevName) - 1] = '\0';
  1583.     }
  1584. }
  1585.  
  1586. /* Get the current stream pointer */
  1587.  
  1588. void
  1589. plgpls(PLStream **p_pls)
  1590. {
  1591.     *p_pls = plsc;
  1592. }
  1593.  
  1594. /* Set the function pointer for the keyboard event handler */
  1595.  
  1596. void
  1597. plsKeyEH(void (*KeyEH) (PLKey *, void *, int *), void *KeyEH_data)
  1598. {
  1599.     plsc->KeyEH = KeyEH;
  1600.     plsc->KeyEH_data = KeyEH_data;
  1601. }
  1602.  
  1603. /* Set the function pointer for the mouse event handler */
  1604.  
  1605. void
  1606. plsMouseEH(void (*MouseEH) (PLMouse *, void *, int *), void *MouseEH_data)
  1607. {
  1608.     plsc->MouseEH = MouseEH;
  1609.     plsc->MouseEH_data = MouseEH_data;
  1610. }
  1611.  
  1612. /* Set orientation.  Must be done before calling plinit. */
  1613.  
  1614. void
  1615. c_plsori(PLINT ori)
  1616. {
  1617.     plsdiori((PLFLT) ori);
  1618. }
  1619.  
  1620. /*
  1621.  * Set pen width.  Can be done any time, but before calling plinit is best
  1622.  * since otherwise it may be volatile (i.e. reset on next page advance).
  1623.  * If width <= 0 or is unchanged by the call, nothing is done.
  1624.  */
  1625.  
  1626. void
  1627. c_plwid(PLINT width)
  1628. {
  1629.     if (width != plsc->width && width > 0) {
  1630.     plsc->width = width;
  1631.  
  1632.     if (plsc->level > 0) {
  1633.         if ( ! plsc->widthlock)
  1634.         plP_state(PLSTATE_WIDTH);
  1635.     }
  1636.     }
  1637. }
  1638.  
  1639. /* Obsolete.  Use page driver interface instead. */
  1640.  
  1641. void
  1642. c_plsasp(PLFLT asp)
  1643. {
  1644. }
  1645.  
  1646. /* I've canned this for now */
  1647.  
  1648. void
  1649. c_plslpb(PLFLT lpbxmi, PLFLT lpbxma, PLFLT lpbymi, PLFLT lpbyma)
  1650. {
  1651. }
  1652.  
  1653. /* Set the output file pointer */
  1654.  
  1655. void
  1656. plgfile(FILE **p_file)
  1657. {
  1658.     *p_file = plsc->OutFile;
  1659. }
  1660.  
  1661. /* Get the output file pointer */
  1662.  
  1663. void
  1664. plsfile(FILE *file)
  1665. {
  1666.     plsc->OutFile = file;
  1667. }
  1668.  
  1669. /* Get the (current) output file name.  Must be preallocated to >80 bytes */
  1670. /* Beyond that, I truncate it.  You have been warned. */
  1671.  
  1672. void
  1673. c_plgfnam(char *fnam)
  1674. {
  1675.     strncpy(fnam, plsc->FileName, 79);
  1676.     fnam[79] = '\0';
  1677. }
  1678.  
  1679. /* Set the output file name. */
  1680.  
  1681. void
  1682. c_plsfnam(const char *fnam)
  1683. {
  1684.     plP_sfnam(plsc, fnam);
  1685. }
  1686.  
  1687. /* Set the pause (on end-of-page) status */
  1688.  
  1689. void
  1690. c_plspause(PLINT pause)
  1691. {
  1692.     plsc->nopause = ! pause;
  1693. }
  1694.  
  1695. /* Set the floating point precision (in number of places) in numeric labels. */
  1696.  
  1697. void
  1698. c_plprec(PLINT setp, PLINT prec)
  1699. {
  1700.     plsc->setpre = setp;
  1701.     plsc->precis = prec;
  1702. }
  1703.  
  1704. /* Get the floating point precision (in number of places) in numeric labels. */
  1705.  
  1706. void
  1707. plP_gprec(PLINT *p_setp, PLINT *p_prec)
  1708. {
  1709.     *p_setp = plsc->setpre;
  1710.     *p_prec = plsc->precis;
  1711. }
  1712.  
  1713. /*
  1714.  * Set the escape character for text strings.
  1715.  * From C you can pass as a character, from Fortran it needs to be the decimal
  1716.  * ASCII value.  Only selected characters are allowed to prevent the user from
  1717.  * shooting himself in the foot (a '\' isn't allowed since it conflicts with
  1718.  * C's use of backslash as a character escape).
  1719.  */
  1720.  
  1721. void
  1722. c_plsesc(char esc)
  1723. {
  1724.     switch (esc) {
  1725.     case '!':        /* ASCII 33 */
  1726.     case '#':        /* ASCII 35 */
  1727.     case '$':        /* ASCII 36 */
  1728.     case '%':        /* ASCII 37 */
  1729.     case '&':        /* ASCII 38 */
  1730.     case '*':        /* ASCII 42 */
  1731.     case '@':        /* ASCII 64 */
  1732.     case '^':        /* ASCII 94 */
  1733.     case '~':        /* ASCII 126 */
  1734.     plsc->esc = esc;
  1735.     break;
  1736.  
  1737.       default:
  1738.     plwarn("plsesc: Invalid escape character, ignoring.");
  1739.     }
  1740. }
  1741.  
  1742. /* Get the escape character for text strings. */
  1743.  
  1744. void
  1745. plgesc(char *p_esc)
  1746. {
  1747.     if (plsc->esc == '\0')
  1748.     plsc->esc = '#';
  1749.  
  1750.     *p_esc = plsc->esc;
  1751. }
  1752.  
  1753. /* Get the current library version number */
  1754. /* Note: you MUST have allocated space for this (80 characters is safe) */
  1755.  
  1756. void
  1757. c_plgver(char *p_ver)
  1758. {
  1759.     strcpy(p_ver, PLPLOT_VERSION);
  1760. }
  1761.  
  1762. /* Set inferior X window */
  1763.  
  1764. void
  1765. plsxwin(PLINT window_id)
  1766. {
  1767.     plsc->window_id = window_id;
  1768. }
  1769.  
  1770. /*----------------------------------------------------------------------*\
  1771.  *  These set/get information for family files, and may be called prior
  1772.  *  to plinit to set up the necessary parameters.  Arguments:
  1773.  *
  1774.  *    fam    familying flag (boolean)
  1775.  *    num    member number
  1776.  *    bmax    maximum member size
  1777. \*----------------------------------------------------------------------*/
  1778.  
  1779. /* Get family file parameters */
  1780.  
  1781. void
  1782. c_plgfam(PLINT *p_fam, PLINT *p_num, PLINT *p_bmax)
  1783. {
  1784.     *p_fam = plsc->family;
  1785.     *p_num = plsc->member;
  1786.     *p_bmax = plsc->bytemax;
  1787. }
  1788.  
  1789. /* Set family file parameters */
  1790.  
  1791. void
  1792. c_plsfam(PLINT fam, PLINT num, PLINT bmax)
  1793. {
  1794.     if (plsc->level > 0)
  1795.     plwarn("plsfam: Must be called before plinit.");
  1796.  
  1797.     if (fam >= 0)
  1798.     plsc->family = fam;
  1799.     if (num >= 0)
  1800.     plsc->member = num;
  1801.     if (bmax >= 0)
  1802.     plsc->bytemax = bmax;
  1803. }
  1804.  
  1805. /* Advance to the next family file on the next new page */
  1806.  
  1807. void
  1808. c_plfamadv(void)
  1809. {
  1810.     plsc->famadv = 1;
  1811. }
  1812.  
  1813. /*----------------------------------------------------------------------*\
  1814.  *  Interface routines for axis labling parameters.
  1815.  *  See pldtik.c for more info.
  1816. \*----------------------------------------------------------------------*/
  1817.  
  1818. /* Get x axis labeling parameters */
  1819.  
  1820. void
  1821. c_plgxax(PLINT *p_digmax, PLINT *p_digits)
  1822. {
  1823.     *p_digmax = plsc->xdigmax;
  1824.     *p_digits = plsc->xdigits;
  1825. }
  1826.  
  1827. /* Set x axis labeling parameters */
  1828.  
  1829. void
  1830. c_plsxax(PLINT digmax, PLINT digits)
  1831. {
  1832.     plsc->xdigmax = digmax;
  1833.     plsc->xdigits = digits;
  1834. }
  1835.  
  1836. /* Get y axis labeling parameters */
  1837.  
  1838. void
  1839. c_plgyax(PLINT *p_digmax, PLINT *p_digits)
  1840. {
  1841.     *p_digmax = plsc->ydigmax;
  1842.     *p_digits = plsc->ydigits;
  1843. }
  1844.  
  1845. /* Set y axis labeling parameters */
  1846.  
  1847. void
  1848. c_plsyax(PLINT digmax, PLINT digits)
  1849. {
  1850.     plsc->ydigmax = digmax;
  1851.     plsc->ydigits = digits;
  1852. }
  1853.  
  1854. /* Get z axis labeling parameters */
  1855.  
  1856. void
  1857. c_plgzax(PLINT *p_digmax, PLINT *p_digits)
  1858. {
  1859.     *p_digmax = plsc->zdigmax;
  1860.     *p_digits = plsc->zdigits;
  1861. }
  1862.  
  1863. /* Set z axis labeling parameters */
  1864.  
  1865. void
  1866. c_plszax(PLINT digmax, PLINT digits)
  1867. {
  1868.     plsc->zdigmax = digmax;
  1869.     plsc->zdigits = digits;
  1870. }
  1871.  
  1872. /* Get character default height and current (scaled) height */
  1873.  
  1874. void
  1875. c_plgchr(PLFLT *p_def, PLFLT *p_ht)
  1876. {
  1877.     *p_def = plsc->chrdef;
  1878.     *p_ht = plsc->chrht;
  1879. }
  1880.  
  1881. /*----------------------------------------------------------------------*\
  1882.  *  These should not be called by the user.
  1883. \*----------------------------------------------------------------------*/
  1884.  
  1885. /* Get x-y domain in world coordinates for 3d plots */
  1886.  
  1887. void
  1888. plP_gdom(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
  1889. {
  1890.     *p_xmin = plsc->domxmi;
  1891.     *p_xmax = plsc->domxma;
  1892.     *p_ymin = plsc->domymi;
  1893.     *p_ymax = plsc->domyma;
  1894. }
  1895.  
  1896. /* Get vertical (z) scale parameters for 3-d plot */
  1897.  
  1898. void
  1899. plP_grange(PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax)
  1900. {
  1901.     *p_zscl = plsc->zzscl;
  1902.     *p_zmin = plsc->ranmi;
  1903.     *p_zmax = plsc->ranma;
  1904. }
  1905.  
  1906. /* Get parameters used in 3d plots */
  1907.  
  1908. void
  1909. plP_gw3wc(PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz)
  1910. {
  1911.     *p_dxx = plsc->cxx;
  1912.     *p_dxy = plsc->cxy;
  1913.     *p_dyx = plsc->cyx;
  1914.     *p_dyy = plsc->cyy;
  1915.     *p_dyz = plsc->cyz;
  1916. }
  1917.  
  1918. /* Get viewport boundaries in physical coordinates */
  1919.  
  1920. void
  1921. plP_gvpp(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
  1922. {
  1923.     *p_ixmin = plsc->vppxmi;
  1924.     *p_ixmax = plsc->vppxma;
  1925.     *p_iymin = plsc->vppymi;
  1926.     *p_iymax = plsc->vppyma;
  1927. }
  1928.  
  1929. /* Set viewport boundaries in physical coordinates */
  1930.  
  1931. void
  1932. plP_svpp(PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax)
  1933. {
  1934.     plsc->vppxmi = ixmin;
  1935.     plsc->vppxma = ixmax;
  1936.     plsc->vppymi = iymin;
  1937.     plsc->vppyma = iymax;
  1938. }
  1939.  
  1940. /* Get subpage boundaries in physical coordinates */
  1941.  
  1942. void
  1943. plP_gspp(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
  1944. {
  1945.     *p_ixmin = plsc->sppxmi;
  1946.     *p_ixmax = plsc->sppxma;
  1947.     *p_iymin = plsc->sppymi;
  1948.     *p_iymax = plsc->sppyma;
  1949. }
  1950.  
  1951. /* Get clip boundaries in physical coordinates */
  1952.  
  1953. void
  1954. plP_gclp(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
  1955. {
  1956.     *p_ixmin = plsc->clpxmi;
  1957.     *p_ixmax = plsc->clpxma;
  1958.     *p_iymin = plsc->clpymi;
  1959.     *p_iymax = plsc->clpyma;
  1960. }
  1961.  
  1962. /* Set clip boundaries in physical coordinates */
  1963.  
  1964. void
  1965. plP_sclp(PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax)
  1966. {
  1967.     plsc->clpxmi = ixmin;
  1968.     plsc->clpxma = ixmax;
  1969.     plsc->clpymi = iymin;
  1970.     plsc->clpyma = iymax;
  1971. }
  1972.  
  1973. /* Get physical device limits in physical coordinates */
  1974.  
  1975. void
  1976. plP_gphy(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
  1977. {
  1978.     *p_ixmin = plsc->phyxmi;
  1979.     *p_ixmax = plsc->phyxma;
  1980.     *p_iymin = plsc->phyymi;
  1981.     *p_iymax = plsc->phyyma;
  1982. }
  1983.  
  1984. /* Set physical device limits in physical coordinates */
  1985.  
  1986. void
  1987. plP_sphy(PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax)
  1988. {
  1989.     plsc->phyxmi = ixmin;
  1990.     plsc->phyxma = ixmax;
  1991.     plsc->phyymi = iymin;
  1992.     plsc->phyyma = iymax;
  1993. }
  1994.  
  1995. /* Get number of subpages on physical device and current subpage */
  1996.  
  1997. void
  1998. plP_gsub(PLINT *p_nx, PLINT *p_ny, PLINT *p_cs)
  1999. {
  2000.     *p_nx = plsc->nsubx;
  2001.     *p_ny = plsc->nsuby;
  2002.     *p_cs = plsc->cursub;
  2003. }
  2004.  
  2005. /* Set number of subpages on physical device and current subpage */
  2006.  
  2007. void
  2008. plP_ssub(PLINT nx, PLINT ny, PLINT cs)
  2009. {
  2010.     plsc->nsubx = nx;
  2011.     plsc->nsuby = ny;
  2012.     plsc->cursub = cs;
  2013. }
  2014.  
  2015. /* Get font and color attributes */
  2016.  
  2017. void
  2018. plP_gatt(PLINT *p_ifnt, PLINT *p_icol0)
  2019. {
  2020.     *p_ifnt = font;
  2021.     *p_icol0 = plsc->icol0;
  2022. }
  2023.  
  2024. /* Set font and color attributes */
  2025.  
  2026. void
  2027. plP_satt(PLINT ifnt, PLINT icol0)
  2028. {
  2029.     font = ifnt;
  2030.     plsc->icol0 = icol0;
  2031. }
  2032.  
  2033. /* Get subpage boundaries in normalized device coordinates */
  2034.  
  2035. void
  2036. plP_gspd(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
  2037. {
  2038.     *p_xmin = plsc->spdxmi;
  2039.     *p_xmax = plsc->spdxma;
  2040.     *p_ymin = plsc->spdymi;
  2041.     *p_ymax = plsc->spdyma;
  2042. }
  2043.  
  2044. /* Get viewport boundaries in normalized device coordinates */
  2045.  
  2046. void
  2047. plP_gvpd(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
  2048. {
  2049.     *p_xmin = plsc->vpdxmi;
  2050.     *p_xmax = plsc->vpdxma;
  2051.     *p_ymin = plsc->vpdymi;
  2052.     *p_ymax = plsc->vpdyma;
  2053. }
  2054.  
  2055. /* Get viewport boundaries in normalized device coordinates */
  2056.  
  2057. void
  2058. plP_svpd(PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax)
  2059. {
  2060.     plsc->vpdxmi = xmin;
  2061.     plsc->vpdxma = xmax;
  2062.     plsc->vpdymi = ymin;
  2063.     plsc->vpdyma = ymax;
  2064. }
  2065.  
  2066. /* Get viewport boundaries in world coordinates */
  2067.  
  2068. void
  2069. plP_gvpw(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
  2070. {
  2071.     *p_xmin = plsc->vpwxmi;
  2072.     *p_xmax = plsc->vpwxma;
  2073.     *p_ymin = plsc->vpwymi;
  2074.     *p_ymax = plsc->vpwyma;
  2075. }
  2076.  
  2077. /* Set viewport boundaries in world coordinates */
  2078.  
  2079. void
  2080. plP_svpw(PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax)
  2081. {
  2082.     plsc->vpwxmi = xmin;
  2083.     plsc->vpwxma = xmax;
  2084.     plsc->vpwymi = ymin;
  2085.     plsc->vpwyma = ymax;
  2086. }
  2087.  
  2088. /* Get number of pixels to a millimeter */
  2089.  
  2090. void
  2091. plP_gpixmm(PLFLT *p_x, PLFLT *p_y)
  2092. {
  2093.     *p_x = plsc->xpmm;
  2094.     *p_y = plsc->ypmm;
  2095. }
  2096.  
  2097. /* Set number of pixels to a millimeter */
  2098.  
  2099. void
  2100. plP_spixmm(PLFLT x, PLFLT y)
  2101. {
  2102.     plsc->xpmm = x;
  2103.     plsc->ypmm = y;
  2104.     plsc->umx = 1000.0 / plsc->xpmm;
  2105.     plsc->umy = 1000.0 / plsc->ypmm;
  2106. }
  2107.  
  2108. /* All the drivers call this to set physical pixels/mm. */
  2109.  
  2110. void
  2111. plP_setpxl(PLFLT xpmm0, PLFLT ypmm0)
  2112. {
  2113.     plsc->xpmm = xpmm0;
  2114.     plsc->ypmm = ypmm0;
  2115.     plsc->umx = 1000.0 / plsc->xpmm;
  2116.     plsc->umy = 1000.0 / plsc->ypmm;
  2117. }
  2118.  
  2119. /* Sets up physical limits of plotting device and the mapping between
  2120.    normalized device coordinates and physical coordinates. */
  2121.  
  2122. void
  2123. plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
  2124. {
  2125.     PLFLT mpxscl, mpyscl;
  2126.  
  2127.     plP_sphy(xmin, xmax, ymin, ymax);
  2128.  
  2129.     plsc->dpxscl = xmax - xmin;
  2130.     plsc->dpxoff = xmin;
  2131.     plsc->dpyscl = ymax - ymin;
  2132.     plsc->dpyoff = ymin;
  2133.  
  2134.     mpxscl = plsc->xpmm;
  2135.     if (xmax <= xmin)
  2136.     mpxscl = -plsc->xpmm;
  2137.     mpyscl = plsc->ypmm;
  2138.     if (ymax <= ymin)
  2139.     mpyscl = -plsc->ypmm;
  2140.     plP_smp(mpxscl, (PLFLT) (xmin), mpyscl, (PLFLT) (ymin));
  2141. }
  2142.  
  2143. /* Get transformation variables for world coordinates to mm */
  2144.  
  2145. void
  2146. plP_gwm(PLFLT *p_xscl, PLFLT *p_xoff, PLFLT *p_yscl, PLFLT *p_yoff)
  2147. {
  2148.     *p_xscl = plsc->wmxscl;
  2149.     *p_xoff = plsc->wmxoff;
  2150.     *p_yscl = plsc->wmyscl;
  2151.     *p_yoff = plsc->wmyoff;
  2152. }
  2153.  
  2154. /* Set transformation variables for world coordinates to mm */
  2155.  
  2156. void
  2157. plP_swm(PLFLT xscl, PLFLT xoff, PLFLT yscl, PLFLT yoff)
  2158. {
  2159.     plsc->wmxscl = xscl;
  2160.     plsc->wmxoff = xoff;
  2161.     plsc->wmyscl = yscl;
  2162.     plsc->wmyoff = yoff;
  2163. }
  2164.  
  2165. /* Get transformation variables for millimeters from bottom left */
  2166.  
  2167. void
  2168. plP_gmp(PLFLT *p_xscl, PLFLT *p_xoff, PLFLT *p_yscl, PLFLT *p_yoff)
  2169. {
  2170.     *p_xscl = plsc->mpxscl;
  2171.     *p_xoff = plsc->mpxoff;
  2172.     *p_yscl = plsc->mpyscl;
  2173.     *p_yoff = plsc->mpyoff;
  2174. }
  2175.  
  2176. /* Set transformation variables for millimeters from bottom left */
  2177.  
  2178. void
  2179. plP_smp(PLFLT xscl, PLFLT xoff, PLFLT yscl, PLFLT yoff)
  2180. {
  2181.     plsc->mpxscl = xscl;
  2182.     plsc->mpxoff = xoff;
  2183.     plsc->mpyscl = yscl;
  2184.     plsc->mpyoff = yoff;
  2185. }
  2186.